package com.by.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.SpringVersion;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.config.annotation.*;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.EnumSet;
import java.util.List;

/**
 * @author LittleDesire
 * @description
 * @date 2022-03-22 周二 20:30
 * @since 17
 */
@Configuration
@EnableWebMvc
@RestController
@ComponentScan("com.by.controller")
public class WebInit implements WebApplicationInitializer,WebMvcConfigurer {

   /**
    * 启动注册
    * @param servletContext 服务容器
    */
   @Override
   public void onStartup(ServletContext servletContext) {
       AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
       ctx.register(this.getClass());
       ctx.setServletContext(servletContext);
       // 服务调度器
       ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
       dispatcher.addMapping("/");
       dispatcher.setLoadOnStartup(1);

       // 字符编码过滤器
       CharacterEncodingFilter cef = new CharacterEncodingFilter("UTF-8");
       FilterRegistration.Dynamic frd = servletContext.addFilter("cef", cef);
       // 解决PrintWriter out 输出乱码 若解决不了 继承 官方CharacterEncodingFilter的类重写 doFilterInternal方法 添加请求响应编码
       frd.setInitParameter("forceRequestEncoding", "true");
       frd.setInitParameter("forceResponseEncoding", "true");
       frd.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD), true, "/*","/api/*");
   }

   /**
    * 静态资源处理器
    * @param registry 注册
    */
   @Override
   public void addResourceHandlers(ResourceHandlerRegistry registry) {
       registry.addResourceHandler("/**/*.html").addResourceLocations("/");
       registry.addResourceHandler("/img/**").addResourceLocations("/img/");
       registry.addResourceHandler("/css/**").addResourceLocations("/css/");
       registry.addResourceHandler("/js/**").addResourceLocations("/js/");
       registry.addResourceHandler("/**/*.*").addResourceLocations("/static/");
   }


   /**
    * 消息转换器
    * @param converters 转换器
    */
   @Override
   public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
       StringHttpMessageConverter shmc = new StringHttpMessageConverter();
       shmc.setDefaultCharset(StandardCharsets.UTF_8);
       List<MediaType> mediaTypes = List.of(MediaType.parseMediaType("text/html;charset=UTF-8"));
       shmc.setSupportedMediaTypes(mediaTypes);
       converters.add(shmc);


       //如下配置需要引入jackson组件，主要解决json输出，面向接口开发用的 (jackson-databind jackson-datatype-jsr310)
       MappingJackson2HttpMessageConverter mjhmc = new MappingJackson2HttpMessageConverter();
       ObjectMapper objectMapper = new ObjectMapper();
       JavaTimeModule jtm = new JavaTimeModule();
       //LocalDateTime
       jtm.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
       jtm.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
       //LocalDate
       jtm.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
       jtm.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
       //LocalTime
       jtm.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
       jtm.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
       objectMapper.registerModule(jtm);
       //java.util.Date //设置日期格式
       SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
       objectMapper.setDateFormat(sdf);
       mjhmc.setObjectMapper(objectMapper);
       //设置中文编码格式
       mjhmc.setSupportedMediaTypes(List.of(MediaType.parseMediaType("application/json;charset=UTF-8")));
       converters.add(mjhmc);
   }


    /**
     * 视图解析器
     * @param registry 注册
     */
    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        InternalResourceViewResolver irvr = new InternalResourceViewResolver();
        irvr.setPrefix("/WEB-INF/templates/");
        irvr.setSuffix(".jsp");
        registry.viewResolver(irvr);
    }

    @RequestMapping("/")
    public String index() {
        return String.format("Hello 爪哇 [%s]", SpringVersion.getVersion());
    }

    // 乱码
    @RequestMapping("p1")
    public void p1(PrintWriter out) {
        out.printf("p1 乱码 [%s]", SpringVersion.getVersion());
    }

    // 没有乱码
    @RequestMapping("/p2")
    public void p2(HttpServletResponse resp) throws IOException {
        resp.setCharacterEncoding("utf-8");
        resp.setContentType("text/html;charset=utf-8");
        PrintWriter out = resp.getWriter();
        out.printf("p1 没有乱码 [%s]", SpringVersion.getVersion());
        out.flush();
        out.close();
    }

    // 默认请求/默认参数 get 不乱码，  传入参数 post 乱码 配置消息转换器
    @RequestMapping("/p3")
    public String p3(@RequestParam(name="name",required = false,defaultValue = "刻晴")String name, HttpServletRequest req) {
        return String.format("名字：%s。方法：%s" , name,req.getMethod());
    }
}
